// map.go
package main

import (
	// "fmt"
	"log"
	"strings"
)

const worldSize = 2

type Direction int

const (
	north Direction = iota
	northeast
	east
	southeast
	south
	southwest
	west
	northwest
	up
	down
)

type Coords struct {
	X, Y int
}

func (this *Coords) Move(destination Direction) *Coords {
	return &Coords{this.X + directions[destination].offset.X, this.Y + directions[destination].offset.Y}
}

type direction struct {
	Name, Shortname string
	offset          Coords
}

var directions = []direction{
	north: {"north", "n", Coords{0, +1}},
	east:  {"east", "e", Coords{+1, +0}},
	south: {"south", "s", Coords{0, -1}},
	west:  {"west", "w", Coords{-1, 0}},
}

type Place struct {
	name        string
	description string
	coords      Coords
	neighbours  map[Direction]*Place
	items       []Entity
}

// implements Entity
func (this Place) Name() string {
	return this.name
}

// implements Entity
func (this *Place) Description(beholder Entity) string {
	description := this.description + "\n\nYou can see here: "
	itemNames := []string{}
	log.Printf("Description(): items an dem Ort: %v", &this.items)
	for i, _ := range this.items {
		if this.items[i] != beholder {
			itemNames = append(itemNames, this.items[i].Name())
		}
	}
	if len(itemNames) == 0 {
		description += "Nothing special."
	} else {
		description += strings.Join(itemNames, ", ") + "."
	}

	directionList := []string{}
	for direction := range this.neighbours {
		directionList = append(directionList, directions[direction].Name)
	}
	description += "\n\nYou can go: " + strings.Join(directionList, ", ") + "."

	return description
}

func (this *Place) put(item Entity) {
	log.Printf("put(): item list before put is: %+v", this.items)
	this.items = append(this.items, item)
	log.Printf("put(): item list after put is: %+v", this.items)
}

func (this *Place) remove(item Entity) {
	log.Printf("remove(): Given item is %v", item)
	log.Printf("remove(): Items at this place before removing: %v", &this.items)
	for i, _ := range this.items {
		if item == this.items[i] {
			this.items = append(this.items[:i], this.items[i+1:]...)
			break
		}
	}

	log.Printf("removeEntity(): Items at this place after removing: %v", &this.items)
	return
}

type Area struct {
	Name   string
	places [][]Place
}

func NewArea(name string, size int) *Area {
	area := Area{name, make([][]Place, worldSize)}
	for i := range area.places {
		area.places[i] = make([]Place, worldSize)
	}
	for i := 0; i < worldSize; i++ {
		for j := 0; j < worldSize; j++ {
			area.places[i][j].coords = Coords{i, j}
		}
	}

	return &area
}

func (this *Area) Place(location *Coords) *Place {
	return &this.places[location.X][location.Y]
}

//func move(creature Creature, start *Place, to string) {
//	directions := getValidDirections(start)
//	direction, isValid := directions[to]
//	if !isValid {
//		panic("Invalid Direction")
//	}

//	location := start.coords.Move(direction)
//	log.Printf("moveEntity(): neue Koordinaten: %v", location)
//	log.Printf("moveEntity(): world places before put: %+v", world.places)

//	start.remove(creature)

//	world.Place(location).put(creature)

//	return

//}

//func getValidDirections(place *Place) map[string]Direction {

//	validDirections := map[string]Direction{}
//	for id, direction := range directions {
//		if IsValidLocation(place.coords.Move(direction)) {
//			log.Printf("getValidDirections(): direction %v is valid. Append it to valid directions.", direction)
//			validDirections[id] = direction
//		}
//	}

//	return validDirections

//}

func IsValidLocation(coords *Coords) bool {
	return coords.X >= 0 && coords.X < worldSize &&
		coords.Y >= 0 && coords.Y < worldSize

}

func NewWorld() *Area {

	world := NewArea("The Counryside", worldSize)

	var place *Place

	place = world.Place(&Coords{0, 0})
	place.name = "The Birth Place"
	place.description = "The place where it all begins. A nice spot at the edge of town."
	place.neighbours = make(map[Direction]*Place)
	place.neighbours[north] = world.Place(&Coords{0, 1})
	place.neighbours[east] = world.Place(&Coords{1, 0})

	place = world.Place(&Coords{0, 1})
	place.name = "The Old Tree"
	place.description = "A quiet place with an old tree and a fontaine."

	place = world.Place(&Coords{1, 0})
	place.name = "The Blue River"
	place.description = "The river flows slowly, it has a shallow shore."

	place = world.Place(&Coords{1, 1})
	place.name = "The Forest"
	place.description = "It's a dark place with all the trees. You here no sound."

	return world
}

func NewHome() *Area {

	home := NewArea("Home, Sweet Home", worldSize)

	var place *Place
	place = home.Place(&Coords{0, 0})
	place.name = "The Corridor"
	place.description = "A simple Room."

	place = home.Place(&Coords{0, 1})
	place.name = "The Kitchen"
	place.description = "A well furnished kitchen."

	place = home.Place(&Coords{1, 0})
	place.name = "The Living Room"
	place.description = "A comfy room woth TV, couch and some flours."

	place = home.Place(&Coords{1, 1})
	place.name = "The Bedroom"
	place.description = "The Place Of Sin, haha."

	return home

}
